home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / animutil / fastgfx / fg303b / manuals.arj / USER14.DOC < prev    next >
Encoding:
Text File  |  1993-10-02  |  66.7 KB  |  1,430 lines

  1. Chapter 14
  2.  
  3.  
  4.  
  5.  
  6.  
  7. Input Device Support
  8.  
  9. 260   Fastgraph User's Guide
  10.  
  11.  
  12. Overview
  13.  
  14.      The selection of application input devices is an important part of
  15. designing a program for the IBM PC and PS/2 family of systems.  The keyboard
  16. and mouse are the most popular, and in fact more and more applications,
  17. especially those that use a graphical interface, actually require a mouse to
  18. use the product.  Another input device, primarily used in entertainment
  19. software, is the joystick.  Although not as popular as the mouse, joysticks
  20. nevertheless can simplify the use of certain applications.  Fastgraph
  21. provides support for these three types of input devices, and this chapter
  22. will discuss this in detail.
  23.  
  24.  
  25. Keyboard Support
  26.  
  27.      Fastgraph's keyboard support includes routines to read keystrokes, check
  28. the state of certain keys, and set the state of these keys.  In addition,
  29. Fastgraph provides a low-level keyboard handler that replaces the BIOS
  30. keyboard handler to increase keyboard responsiveness.  These routines are
  31. independent of the other parts of Fastgraph and thus do not require that you
  32. call fg_setmode.  All keyboard-related routines work in text and graphics
  33. video modes.
  34.  
  35.      The IBM PC and PS/2 keyboards produce two types of character codes --
  36. standard codes and extended codes (extended codes are sometimes called
  37. auxiliary codes).  The standard codes correspond to the 128 characters in the
  38. ASCII character set.  In general, pressing keys on the main part of the
  39. keyboard, or on the numeric keypad with NumLock turned on, will generate a
  40. standard code.  The 128 extended codes are specific to the IBM PC and PS/2
  41. keyboards.  Some common keystrokes that produce extended codes are keys on
  42. the numeric keypad with NumLock turned off, the function keys, or pressing
  43. Alt with another key.  The following tables show the standard and extended
  44. keyboard codes.
  45.  
  46.                        Table of standard keyboard codes
  47.  
  48.           key     code   key     code   key     code   key     code
  49.  
  50.           (none)    0    space    32    @        64    `        96
  51.           Ctrl+A    1    !        33    A        65    a        97
  52.           Ctrl+B    2    "        34    B        66    b        98
  53.           Ctrl+C    3    #        35    C        67    c        99
  54.           Ctrl+D    4    $        36    D        68    d       100
  55.           Ctrl+E    5    %        37    E        69    e       101
  56.           Ctrl+F    6    &        38    F        70    f       102
  57.           Ctrl+G    7    '        39    G        71    g       103
  58.           Ctrl+H    8    (        40    H        72    h       104
  59.           Ctrl+I    9    )        41    I        73    i       105
  60.           Ctrl+J   10    *        42    J        74    j       106
  61.           Ctrl+K   11    +        43    K        75    k       107
  62.           Ctrl+L   12    ,        44    L        76    l       108
  63.           Ctrl+M   13    -        45    M        77    m       109
  64.           Ctrl+N   14    .        46    N        78    n       110
  65.           Ctrl+O   15    /        47    O        79    o       111
  66.           Ctrl+P   16    0        48    P        80    p       112
  67.           Ctrl+Q   17    1        49    Q        81    q       113
  68.                                        Chapter 14:  Input Device Support   261
  69.  
  70.           Ctrl+R   18    2        50    R        82    r       114
  71.           Ctrl+S   19    3        51    S        83    s       115
  72.           Ctrl+T   20    4        52    T        84    t       116
  73.           Ctrl+U   21    5        53    U        85    u       117
  74.           Ctrl+V   22    6        54    V        86    v       118
  75.           Ctrl+W   23    7        55    W        87    w       119
  76.           Ctrl+X   24    8        56    X        88    x       120
  77.           Ctrl+Y   25    9        57    Y        89    y       121
  78.           Ctrl+Z   26    :        58    Z        90    z       122
  79.           Ctrl+[   27    ;        59    [        91    {       123
  80.           Ctrl+\   28    <        60    \        92    |       124
  81.           Ctrl+]   29    =        61    ]        93    }       125
  82.           Ctrl+^   30    >        62    ^        94    ~       126
  83.           Ctrl+-   31    ?        63    _        95    Ctrl+BS 127
  84.  
  85.  
  86.                        Table of extended keyboard codes
  87.  
  88.               code        key
  89.  
  90.                3          Ctrl+@
  91.               15          Shift+Tab (back tab)
  92.               16-25       Alt+Q to Alt+P (top row of letters)
  93.               30-38       Alt+A to Alt+L (middle row of letters)
  94.               44-50       Alt+Z to Alt+M (bottom row of letters)
  95.               59-68       F1 to F10
  96.               71          Home
  97.               72          up arrow
  98.               73          PgUp
  99.               75          left arrow
  100.               77          right arrow
  101.               79          End
  102.               80          down arrow
  103.               81          PgDn
  104.               82          Ins
  105.               83          Del
  106.               84-93       Shift+F1 to Shift+F10
  107.               94-103      Ctrl+F1 to Ctrl+F10
  108.               104-113     Alt+F1 to Alt+F10
  109.               114         Ctrl+PrtSc
  110.               115         Ctrl+left arrow
  111.               116         Ctrl+right arrow
  112.               117         Ctrl+End
  113.               118         Ctrl+PgDn
  114.               119         Ctrl+Home
  115.               120-131     Alt+1 to Alt+= (top row of keys)
  116.               132         Ctrl+PgUp
  117.  
  118. In addition, four keys generate the same standard codes as other control key
  119. combinations.  These keys are:
  120.  
  121.                          key       same as   code
  122.  
  123.                          Backspace Ctrl+H      8
  124.                          Tab       Ctrl+I      9
  125.                          Enter     Ctrl+M     13
  126.                          Escape    Ctrl+[     27
  127. 262   Fastgraph User's Guide
  128.  
  129.  
  130.      The CapsLock, NumLock, and ScrollLock keys do not generate a standard or
  131. extended code when pressed.  Instead, they toggle between off and on states.
  132.  
  133.  
  134. Reading Keystrokes
  135.  
  136.      When you press a key or key combination, the standard or extended code
  137. representing that keystroke is stored in the ROM BIOS keyboard buffer.  This
  138. buffer can hold up to 16 keystrokes and thus provides a type-ahead
  139. capability.  Fastgraph includes three routines for reading keystroke
  140. information from the keyboard buffer.  The fg_getkey routine reads the next
  141. item in the keyboard buffer if one is available (that is, if a key has been
  142. pressed).  If the keyboard buffer is empty (meaning no key has been pressed),
  143. fg_getkey waits for a keystroke and then reports information about it.
  144. Another routine, fg_intkey, reads the next keystroke from the keyboard buffer
  145. if one is available.  If the keyboard buffer is empty, fg_intkey immediately
  146. returns and reports this condition.  The fg_intkey routine is useful when a
  147. program must continue performing a task until a key is pressed.  We've
  148. already seen the third routine, fg_waitkey, which flushes the keyboard buffer
  149. and then waits for another keystroke.  Unlike fg_getkey and fg_intkey,
  150. fg_waitkey does not return any keystroke information.  It is most useful in
  151. "press any key to continue" situations.
  152.  
  153.      Both fg_getkey and fg_intkey require two one-byte arguments passed by
  154. reference.  If the keystroke is represented by a standard keyboard code,
  155. fg_getkey and fg_intkey return its code in the first argument and set the
  156. second argument to zero.  Similarly, if the keystroke generates an extended
  157. code, the routines return its code in the second argument and set the first
  158. argument to zero.  If the fg_intkey routine detects an empty keyboard buffer,
  159. it sets both arguments to zero.
  160.  
  161.      Example 14-1 is a simple program that uses the fg_getkey routine.  It
  162. solicits keystrokes and then displays the two values returned by fg_getkey,
  163. one of which will always be zero.  The variable key receives the key's
  164. standard code, while aux receives its extended code.  Note that fg_getkey is
  165. the only Fastgraph routine in the program; this can be done because the
  166. keyboard support routines are logically independent from the rest of
  167. Fastgraph.  The program returns to DOS when you press the Escape key.
  168.  
  169.                                 Example 14-1.
  170.  
  171.                #include <fastgraf.h>
  172.                #include <stdio.h>
  173.                void main(void);
  174.  
  175.                #define ESC 27
  176.  
  177.                void main()
  178.                {
  179.                   unsigned char key, aux;
  180.  
  181.                   do {
  182.                      fg_getkey(&key,&aux);
  183.                      printf("key = %3d  aux = %3d\n",key,aux);
  184.                      }
  185.  
  186.                                        Chapter 14:  Input Device Support   263
  187.  
  188.  
  189.                   while (key != ESC);
  190.                }
  191.  
  192.  
  193.      Example 14-2 reads keystrokes using the fg_intkey routine at half-second
  194. intervals (18 fg_waitfor units equals one second).  As in the previous
  195. example, the program displays the standard and extended codes for each
  196. keystroke.  However, example 14-2 will continuously execute the while loop
  197. even if no keystrokes are available, in which case the key and aux values
  198. will both be zero.  The program returns to DOS when you press the Escape key.
  199.  
  200.                                 Example 14-2.
  201.  
  202.                #include <fastgraf.h>
  203.                #include <stdio.h>
  204.                void main(void);
  205.  
  206.                #define ESC 27
  207.  
  208.                void main()
  209.                {
  210.                   unsigned char key, aux;
  211.  
  212.                   do {
  213.                      fg_waitfor(9);
  214.                      fg_intkey(&key,&aux);
  215.                      printf("key = %3d  aux = %3d\n",key,aux);
  216.                      }
  217.                   while (key != ESC);
  218.                }
  219.  
  220.      When you use fg_intkey in a "tight" loop that does little else, you
  221. should force a small delay within the loop by calling fg_waitfor as in
  222. example 14-2.  Typically a delay of one or two clock ticks is enough.
  223. Without this delay, the BIOS may not be able to handle all keyboard activity,
  224. and thus some keystrokes may not be available to your program.
  225.  
  226.  
  227. Testing and Setting Key States
  228.  
  229.      As mentioned earlier, the CapsLock, NumLock, and ScrollLock keys do not
  230. generate a standard or extended code when pressed but instead toggle between
  231. off and on states.  Fastgraph includes routines for checking the state of
  232. these keys, as well as setting the state of the CapsLock and NumLock keys.
  233.  
  234.      The Fastgraph routines fg_capslock, fg_numlock, and fg_scrlock
  235. respectively read the state of the CapsLock, NumLock, and ScrollLock keys.
  236. Each routine has no arguments and returns the key state as its function
  237. value.  A return value of 0 means the associated key is in the off state,
  238. while 1 indicates the key is in the on state.  If the keyboard does not have
  239. a ScrollLock key, fg_scrlock considers the key off and returns a value of
  240. zero.
  241.  
  242.      Example 14-3 is a simple program that uses the fg_capslock, fg_numlock,
  243. and fg_scrlock routines to print messages describing the current state of
  244. these three keys.
  245. 264   Fastgraph User's Guide
  246.  
  247.  
  248.  
  249.                                 Example 14-3.
  250.  
  251.                     #include <fastgraf.h>
  252.                     #include <stdio.h>
  253.                     void main(void);
  254.  
  255.                     void main()
  256.                     {
  257.                        if (fg_capslock())
  258.                           printf("CapsLock is on.\n");
  259.                        else
  260.                           printf("CapsLock is off.\n");
  261.  
  262.                        if (fg_numlock())
  263.                           printf("NumLock is on.\n");
  264.                        else
  265.                           printf("NumLock is off.\n");
  266.  
  267.                        if (fg_scrlock())
  268.                           printf("ScrollLock is on.\n");
  269.                        else
  270.                           printf("ScrollLock is off.\n");
  271.                     }
  272.  
  273.      You also can set the state of the CapsLock and NumLock keys within a
  274. program.  Fastgraph includes two routines, fg_setcaps and fg_setnum, for this
  275. purpose.  Each routine requires an integer argument that specifies the new
  276. key state.  If the argument value is 0, the key will be turned off; if the
  277. value is 1, the key will be turned on.  Example 14-4 uses fg_setcaps and
  278. fg_setnum to turn off CapsLock and NumLock.
  279.  
  280.                                 Example 14-4.
  281.  
  282.                             #include <fastgraf.h>
  283.                             void main(void);
  284.  
  285.                             void main()
  286.                             {
  287.                                fg_setcaps(0);
  288.                                fg_setnum(0);
  289.                             }
  290.  
  291.      On most keyboards, changing key states with fg_setcaps or fg_setnum also
  292. will change the keyboard state light to reflect the new key state.  However,
  293. some older keyboards, especially when used on PC, PC/XT, or Tandy 1000
  294. systems, do not update the state light.  This makes the state light
  295. inconsistent with the true key state.
  296.  
  297.  
  298. Low-Level Keyboard Handler
  299.  
  300.      Fastgraph includes a low-level keyboard handler that replaces the BIOS
  301. keyboard handler.  The replacement handler intercepts keystrokes ahead of the
  302. BIOS and thus eliminates the annoying beep that sounds upon filling the BIOS
  303.                                        Chapter 14:  Input Device Support   265
  304.  
  305.  
  306. keyboard buffer.  Fastgraph's keyboard handler is especially well-suited to
  307. game development because it increases keyboard responsiveness in high-speed
  308. action games.  However, when the low-level keyboard handler is enabled, it is
  309. not possible to use fg_getkey, fg_intkey, fg_waitkey, or any third party
  310. functions that use BIOS or DOS services for keyboard activity.  For this
  311. reason, a program that enables the low-level keyboard handler must disable it
  312. before exiting to DOS.
  313.  
  314.      The low-level keyboard handler can be enabled and disabled at any time.
  315. The fg_kbinit routine is provided for this purpose.  To enable Fastgraph's
  316. low-level keyboard handler, pass the value 1 to fg_kbinit.  To disable
  317. Fastgraph's handler and re-enable the BIOS keyboard handler, pass the value
  318. zero.  No harm is caused if you try to enable Fastgraph's keyboard handler
  319. when it is already active, or if you try to disable it when the BIOS handler
  320. is active.
  321.  
  322.      When the low-level keyboard handler is enabled, you can use the
  323. fg_kbtest routine to check if keys are currently pressed or released.  This
  324. routine provides the only mechanism for accessing the keyboard when the low-
  325. level handler is enabled.  It specifies the keys through the use of scan
  326. codes.  If the corresponding key is pressed, fg_kbtest returns 1.  If it is
  327. released, the routine returns zero.  The following table lists the scan codes
  328. returned by pressing the keys on a standard PC keyboard.
  329.  
  330.                              Table of scan codes
  331.  
  332.                   scan           scan           scan           scan
  333.           key     code   key     code   key     code   key     code
  334.  
  335.           Esc       1    I        23    X        45    F9       67
  336.           1         2    O        24    C        46    F10      68
  337.           2         3    P        25    V        47    NumLock  69
  338.           3         4    [        26    B        48    ScrLock  70
  339.           4         5    ]        27    N        49    Home     71
  340.           5         6    Enter    28    M        50    Up arrow 72
  341.           6         7    Ctrl     29    ,        51    PgUp     73
  342.           7         8    A        30    .        52    KP-      74
  343.           8         9    S        31    /        53    L arrow  75
  344.           9        10    D        32    R shift  54    KP5      76
  345.           0        11    F        33    KP*      55    R arrow  77
  346.           -        12    G        34    Alt      56    KP+      78
  347.           =        13    H        35    Space    57    End      79
  348.           BS       14    J        36    CapsLock 58    Dn arrow 80
  349.           Tab      15    K        37    F1       59    PgDn     81
  350.           Q        16    L        38    F2       60    Ins      82
  351.           W        17    ;        39    F3       61    Del      83
  352.           E        18    '        40    F4       62    (unused) 84
  353.           R        19    `        41    F5       63    (unused) 85
  354.           T        20    L shift  42    F6       64    (unused) 86
  355.           Y        21    \        43    F7       65    F11      87
  356.           U        22    Z        44    F8       66    F12      88
  357.  
  358.      There are actually more scan codes defined for PC keyboards than listed
  359. in this table.  Such scan codes are generated when a key is pressed as a
  360. combination of one or more keys, such as when the shift and slash keys are
  361. pressed together to produce a question mark (?) character.  Fastgraph's low-
  362. 266   Fastgraph User's Guide
  363.  
  364.  
  365. level keyboard handler is designed to report the pressing or releasing of
  366. keys themselves, as opposed to reporting the actual characters so produced.
  367. It is thus not possible for the keyboard handler to report the scan code for
  368. a multi-key character.  If needed, such characters can be identified by the
  369. scan codes generated for each individual key in the sequence.  For example, a
  370. question mark character would be reported as a forward slash (scan code 53)
  371. generated while pressing the left shift (42) or right shift (54) keys.
  372.  
  373.      Example 14-5 illustrates the use of Fastgraph's low-level keyboard
  374. handler.  It first uses fg_kbinit to enable Fastgraph's keyboard handler and
  375. displays a message stating this.  Then, at approximately one second
  376. intervals, the program calls fg_kbtest to check which of the four arrow keys
  377. are pressed and displays an appropriate message.  Pressing Escape restores
  378. the BIOS keyboard handler and exits to DOS.
  379.  
  380.                                 Example 14-5.
  381.  
  382.                 #include <fastgraf.h>
  383.                 #include <stdio.h>
  384.                 void main(void);
  385.  
  386.                 #define ESC    1
  387.                 #define LEFT  75
  388.                 #define RIGHT 77
  389.                 #define UP    72
  390.                 #define DOWN  80
  391.  
  392.                 void main()
  393.                 {
  394.                    fg_kbinit(1);
  395.                    printf("Keyboard handler enabled.\n");
  396.  
  397.                    do {
  398.                       printf("keys pressed:  ");
  399.                       if (fg_kbtest(LEFT))   printf("Left ");
  400.                       if (fg_kbtest(RIGHT))  printf("Right ");
  401.                       if (fg_kbtest(UP))     printf("Up ");
  402.                       if (fg_kbtest(DOWN))   printf("Down ");
  403.                       printf("\n");
  404.                       fg_waitfor(18);
  405.                    } while (fg_kbtest(ESC) == 0);
  406.  
  407.                    fg_kbinit(0);
  408.                    printf("Keyboard handler disabled.\n");
  409.                 }
  410.  
  411. Mouse Support
  412.  
  413.      The mouse is a very popular input and pointing device, especially in
  414. graphically-oriented programs.  Fastgraph contains several routines to
  415. support mice.  These routines perform such tasks as mouse initialization,
  416. controlling and defining the mouse cursor, and reporting information about
  417. the mouse position and button status.
  418.  
  419.      The underlying software that controls the mouse is called the mouse
  420. driver.  Fastgraph's mouse support routines provide a high-level interface to
  421.                                        Chapter 14:  Input Device Support   267
  422.  
  423. this driver.  The Microsoft Mouse and its accompanying mouse driver have
  424. become an industry standard, and other manufacturers of mice have also made
  425. their mouse drivers Microsoft compatible.  For this reason, the Fastgraph
  426. mouse support routines assume you are using a Microsoft or compatible mouse
  427. driver.
  428.  
  429.      Unfortunately, not all mouse drivers are created equal.  That is, some
  430. drivers are not Microsoft compatible, even though they may be advertised as
  431. such.  In some cases, these incompatibilities are rather trivial, but others
  432. are significant.  For example, early versions of some third party mouse
  433. drivers had real problems in the EGA graphics modes.  The Microsoft mouse
  434. driver, the Logitech mouse driver (version 3.2 or above), and the DFI mouse
  435. driver (version 3.00 or above) are known to work well with Fastgraph's mouse
  436. support routines.  Any other Microsoft compatible mouse driver also should
  437. work properly.
  438.  
  439.  
  440. Initializing the Mouse
  441.  
  442.      There are two steps required to use Fastgraph's mouse support routines
  443. within an application program.  First, you must install the mouse driver.
  444. This is done before running the application, typically by entering the
  445. command MOUSE at the DOS command prompt.  Second, you must use the Fastgraph
  446. routine fg_mouseini to initialize the mouse within the program.
  447.  
  448.      The fg_mouseini routine has no arguments and returns a "success or
  449. failure" indicator as its function value.  If the return value is -1, it
  450. means fg_mouseini could not initialize the mouse (either because the mouse
  451. driver is not installed, or the driver is installed but the mouse is
  452. physically disconnected).  If fg_mouseini returns a positive integer value,
  453. the mouse initialization was successful.  The value itself indicates the
  454. number of buttons (either 2 or 3) on the mouse.  If you don't call
  455. fg_mouseini, or if fg_mouseini can't initialize the mouse, none of
  456. Fastgraph's other mouse support routines will have any effect.3
  457.  
  458.      Example 14-6 illustrates how to initialize the mouse.  Unlike the
  459. keyboard support routines, Fastgraph's mouse support routines require that
  460. fg_setmode be called first.  In this example, we simply pass fg_setmode the
  461. value -1 to initialize Fastgraph for whatever video mode is in effect when we
  462. run the program.  The program then calls fg_mouseini and prints a message
  463. indicating whether or not the initialization was successful.  If it was, the
  464. message includes the number of buttons on the mouse.
  465.  
  466.                                 Example 14-6.
  467.  
  468.                #include <fastgraf.h>
  469.                #include <stdio.h>
  470.                void main(void);
  471.  
  472.                void main()
  473.                {
  474. ____________________
  475.  
  476.      (3) If you use another mouse library or communicate directly with the
  477.      mouse driver, you must still call fg_mouseini if your program runs in
  478.      modes 13 through 18.  Otherwise, Fastgraph won't know that your program
  479.      is using a mouse and may display graphics incorrectly.
  480. 268   Fastgraph User's Guide
  481.  
  482.  
  483.                   int status;
  484.  
  485.                   fg_setmode(-1);
  486.                   status = fg_mouseini();
  487.  
  488.                   if (status < 0)
  489.                      printf("Mouse not available.\n");
  490.                   else
  491.                      printf("%d button mouse found.\n",status);
  492.                }
  493.  
  494.  
  495.      You should be aware that certain mouse drivers do not fully initialize
  496. the mouse when a program changes video modes.  This problem most frequently
  497. occurs when you restore the original video mode at the end of a program that
  498. has called fg_mouseini.  When changing video modes, you must first make the
  499. mouse cursor invisible (this is described in the next section), change the
  500. video mode, and then call fg_mouseini again to initialize the mouse for the
  501. new video mode.
  502.  
  503.  
  504. XVGA and SVGA Mouse Considerations
  505.  
  506.      Mouse drivers do not have the ability to directly display the mouse
  507. cursor in XVGA and SVGA graphics modes (modes 20 to 29).  Hence, Fastgraph
  508. must display the mouse cursor through an interrupt handler that is activated
  509. whenever the mouse moves.  The handler is automatically installed when you
  510. call fg_mouseini in modes 20 to 29.
  511.  
  512.      If you do not disable this handler before your program exits, it will
  513. remain "hooked" to the mouse driver.  This will most likely hang your system
  514. the next time you try doing anything of consequence.  The fg_mousefin routine
  515. removes Fastgraph's mouse interrupt handler from the mouse driver.  In XVGA
  516. and SVGA graphics modes, you should call fg_mousefin just before restoring
  517. the original video mode, as illustrated below:
  518.  
  519.  
  520.                             fg_mousefin();
  521.                             fg_setmode(old_mode);
  522.                             fg_reset();
  523.  
  524.  
  525. Again, calling fg_mousefin is required only in XVGA and SVGA graphics modes.
  526. Calling it in other video modes is not applicable, though it causes no
  527. problems.
  528.  
  529.      In the standard VGA/MCGA 256-color mode (mode 19), white pixels in the
  530. mouse cursor are displayed in color 15.  This is inconsistent with other
  531. graphics modes, where the mouse cursor's white pixels are displayed in the
  532. highest-numbered color value available in that mode.  Fastgraph corrects this
  533. inconsistency in XVGA and SVGA 256-color graphics modes by displaying white
  534. mouse cursor pixels in color 255.  Like color 15, color 255 is white by
  535. default.  This allows you to redefine color 15 in your 256-color applications
  536. without interfering with the mouse cursor colors.
  537.                                        Chapter 14:  Input Device Support   269
  538.  
  539.  
  540. Controlling the Mouse Cursor
  541.  
  542.      The mouse cursor indicates the current position of the mouse.  By
  543. default, the cursor is a small white arrow in graphics modes and a one-
  544. character rectangle in text modes.  After you use fg_mouseini to initialize
  545. the mouse, the mouse cursor is invisible.  To make it visible, you must use
  546. the fg_mousevis routine.  This routine has a single integer argument that
  547. defines the mouse cursor visibility.  If it is 0, the mouse cursor will be
  548. invisible; if it is 1, the mouse cursor becomes visible.
  549.  
  550.      If the mouse cursor is in an area of the screen that is being updated,
  551. or if it moves into this area during the update process, you must make the
  552. mouse cursor invisible.  Additionally, when performing any video output in
  553. the native EGA and VGA graphics modes (modes 13 through 18), you also must
  554. make the mouse cursor invisible.  Instead of checking for these conditions,
  555. it is more convenient and efficient to make the mouse cursor invisible during
  556. all screen updates and then make it visible again when the updating is
  557. finished.  Finally, you must make the mouse cursor invisible whenever you
  558. change the visual page number with fg_setvpage.
  559.  
  560.      After you initialize the mouse, the cursor is positioned in the center
  561. of the screen.  Moving the mouse of course changes the cursor position, but
  562. you also can position the mouse cursor with the Fastgraph routine
  563. fg_mousemov.  This routine has two arguments that specify the new horizontal
  564. and vertical cursor position.  The position is expressed in screen space
  565. units for graphics modes, while it is expressed in character cells for text
  566. modes.  The fg_mousemov routine moves the cursor whether or not it is
  567. visible.
  568.  
  569.      Sometimes it is useful to restrict the mouse cursor to a specific area
  570. of the screen.  The Fastgraph routine fg_mouselim prevents the mouse cursor
  571. from moving outside the specified rectangular area.  It requires four
  572. arguments that specify the minimum horizontal coordinate, maximum horizontal
  573. coordinate, minimum vertical coordinate, and maximum vertical coordinate of
  574. this area.  Again, the coordinates are expressed in screen space units for
  575. graphics modes and character cells for text modes.
  576.  
  577.      One of the most important functions of the mouse driver is to translate
  578. the horizontal and vertical mouse movements into a position on the screen.
  579. The mouse reports these movements to the mouse driver in units called mickeys
  580. (one mickey is about 1/200 of an inch).  By default, moving the mouse 8
  581. mickeys in the horizontal direction moves the mouse cursor one horizontal
  582. pixel.  Similarly, moving the mouse 16 mickeys vertically moves the cursor
  583. one vertical pixel.  Fastgraph provides a routine named fg_mousespd that can
  584. change these values, which effectively allows you to control the speed at
  585. which the mouse cursor moves relative to the movement of the mouse itself.
  586. The fg_mousespd routine requires two arguments that define the number of
  587. mickeys required for eight pixels of mouse cursor movement.  The first
  588. argument specifies this for the horizontal direction, and the second for the
  589. vertical direction.
  590.  
  591.      Example 14-7, which runs in any graphics mode, demonstrates the
  592. fg_mousevis, fg_mousemov, fg_mouselim, and fg_mousespd routines.  The program
  593. first establishes the video mode, initializes the mouse, and fills the screen
  594. with a white rectangle.  Next, the program calls fg_mousevis to make the
  595. mouse cursor visible and then calls fg_mouselim to restrict the mouse cursor
  596. 270   Fastgraph User's Guide
  597.  
  598. to an area one-fourth the size of the screen, centered in the middle of the
  599. screen.  At this point you should move the mouse cursor around the screen to
  600. see the effect of fg_mouselim and note the speed at which the cursor moves
  601. relative to the mouse itself.  The program continues when you press any key.
  602.  
  603.      The program then uses fg_mousemov to move the mouse cursor to each
  604. corner of the region established by fg_mouselim.  The call to fg_waitfor
  605. keeps the cursor in each corner for two seconds, unless you move the mouse.
  606. Note how the program tries to move the mouse cursor to each corner of the
  607. screen, but since doing so would move the cursor outside the defined region
  608. of movement, fg_mousemov just positions the cursor at the nearest point
  609. possible within this region.  The last call to fg_mousemov moves the cursor
  610. back to the middle of the screen.  After doing this, the program calls
  611. fg_mousespd to change the mouse cursor speed.  The values passed to
  612. fg_mousespd (16 and 32) are twice the defaults and therefore make you move
  613. the mouse twice as far as before to move the mouse cursor the same distance.
  614. When you run the program, compare the mouse sensitivity to the original
  615. speed.  After a keystroke, the program returns to DOS.
  616.  
  617.                                 Example 14-7.
  618.  
  619.                #include <fastgraf.h>
  620.                #include <stdio.h>
  621.                #include <stdlib.h>
  622.                void main(void);
  623.  
  624.                void main()
  625.                {
  626.                   int maxx, maxy;
  627.                   int old_mode;
  628.  
  629.                   old_mode = fg_getmode();
  630.                   fg_setmode(fg_automode());
  631.  
  632.                   if (fg_mouseini() < 0) {
  633.                      fg_setmode(old_mode);
  634.                      fg_reset();
  635.                      exit(1);
  636.                      }
  637.  
  638.                   maxx = fg_getmaxx();
  639.                   maxy = fg_getmaxy();
  640.                   fg_setcolor(15);
  641.                   fg_rect(0,maxx,0,maxy);
  642.  
  643.                   fg_mousevis(1);
  644.                   fg_mouselim(maxx/4,3*maxx/4,maxy/4,3*maxy/4);
  645.                   fg_waitkey();
  646.  
  647.                   fg_mousemov(0,0);
  648.                   fg_waitfor(36);
  649.                   fg_mousemov(maxx,0);
  650.                   fg_waitfor(36);
  651.                   fg_mousemov(maxx,maxy);
  652.                   fg_waitfor(36);
  653.                   fg_mousemov(0,maxy);
  654.                   fg_waitfor(36);
  655.                                        Chapter 14:  Input Device Support   271
  656.  
  657.                   fg_mousemov(maxx/2,maxy/2);
  658.                   fg_mousespd(16,32);
  659.                   fg_waitkey();
  660.  
  661.                   fg_setmode(old_mode);
  662.                   fg_reset();
  663.                }
  664.  
  665.  
  666.  
  667. Reporting the Mouse Status
  668.  
  669.      It is obviously important to be able to track the mouse position and
  670. button status.  The Fastgraph routines fg_mousepos and fg_mousebut enable you
  671. to do this.
  672.  
  673.      The fg_mousepos routine returns information about the current mouse
  674. cursor position and button status.  It requires three integer arguments, all
  675. passed by reference.  The first two arguments respectively receive the
  676. horizontal and vertical coordinates of the mouse cursor.  These values are
  677. expressed in screen space units for graphics modes and character cells for
  678. text modes.  The third argument receives a three-bit mask containing the
  679. button status as indicated below.
  680.  
  681.                    bit
  682.                  number  meaning
  683.  
  684.                     0    1 if left button pressed, 0 if not
  685.                     1    1 if right button pressed, 0 if not
  686.                     2    1 if middle button pressed, 0 if not
  687.  
  688. For example, if both the left and right buttons are pressed, the button
  689. status will be set to 3.  If the mouse only has two buttons, bit 2 will
  690. always be zero.
  691.  
  692.      Another routine, fg_mousebut, is available for returning the number of
  693. button press or release counts that have occurred since the last check, or
  694. since calling fg_mouseini.  Each mouse button maintains its own separate
  695. counters, so fg_mousebut returns this information for a specific button.
  696. Additionally, fg_mousebut returns the horizontal and vertical position of the
  697. mouse cursor at the time the specified button was last pressed or released.
  698.  
  699.      The fg_mousebut routine takes four integer arguments, of which the last
  700. three are passed by reference.  The first argument specifies the button of
  701. interest (1 means the left button, 2 is the right button, and 3 is the middle
  702. button).  If this value is positive, button press counts will be reported.
  703. If it is negative, release counts will be reported.  The second, third, and
  704. fourth arguments respectively receive the press or release count, the
  705. horizontal mouse cursor position at the time of the last press or release,
  706. and the vertical position at that same time.  If the press or release count
  707. is zero, the mouse cursor position is returned as (0,0).  The coordinate
  708. positions are expressed in screen space units for graphics modes and
  709. character cells for text modes.
  710.  
  711.      Example 14-8 runs in any graphics video mode and illustrates the use of
  712. the fg_mousepos and fg_mousebut routines.  The program first establishes the
  713. video mode and then initializes the mouse (the program exits if the
  714. 272   Fastgraph User's Guide
  715.  
  716. initialization fails).  It next fills the entire screen with a white
  717. rectangle and then calls fg_mousevis to make the mouse cursor visible.
  718.  
  719.      The main part of example 14-8 is a while loop that polls the mouse at
  720. three-second intervals (the call fg_waitfor(54) delays the program for three
  721. seconds).  Within the loop, the program first uses fg_mousebut to get the
  722. number of times the left mouse button was pressed in the last three seconds.
  723. Following this, the fg_mousepos routine gets the current mouse position.  The
  724. program then displays this information in the upper left corner of the
  725. screen; note how fg_mousevis is used to make the cursor invisible during
  726. graphics operations.  The program continues until you press the right mouse
  727. button, checked by the call to fg_mousebut at the end of the loop.
  728.  
  729.                                 Example 14-8.
  730.  
  731.           #include <fastgraf.h>
  732.           #include <stdio.h>
  733.           #include <stdlib.h>
  734.           void main(void);
  735.  
  736.           void main()
  737.           {
  738.              int old_mode;
  739.              int buttons, count;
  740.              int x, y;
  741.              char string[25];
  742.  
  743.              old_mode = fg_getmode();
  744.              fg_setmode(fg_automode());
  745.  
  746.              if (fg_mouseini() < 0) {
  747.                 fg_setmode(old_mode);
  748.                 fg_reset();
  749.                 exit(1);
  750.                 }
  751.  
  752.              fg_setcolor(15);
  753.              fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  754.              fg_mousevis(1);
  755.  
  756.              do {
  757.                 fg_waitfor(54);
  758.                 fg_mousebut(1,&count,&x,&y);
  759.                 fg_mousepos(&x,&y,&buttons);
  760.                 sprintf(string,"X=%3d  Y=%3d  count=%4d",x,y,count);
  761.                 fg_mousevis(0);
  762.                 fg_setcolor(15);
  763.                 fg_rect(0,fg_xconvert(25),0,fg_yconvert(1));
  764.                 fg_setcolor(0);
  765.                 fg_locate(0,0);
  766.                 fg_text(string,24);
  767.                 fg_mousevis(1);
  768.                 fg_mousebut(2,&count,&x,&y);
  769.                 }
  770.              while (count == 0);
  771.  
  772.              fg_setmode(old_mode);
  773.                                        Chapter 14:  Input Device Support   273
  774.  
  775.  
  776.              fg_reset();
  777.           }
  778.  
  779.  
  780. Defining the Mouse Cursor
  781.  
  782.      By default, the mouse cursor is a small white arrow in graphics modes
  783. and a one-character rectangle in text modes.  In graphics modes, you can
  784. change the mouse cursor to any 16 by 16 pixel image with the Fastgraph
  785. routine fg_mouseptr (in the CGA four-color graphics modes, the cursor size is
  786. 8 by 16 pixels).  You cannot change the mouse cursor shape in text modes, but
  787. you can use the Fastgraph routine fg_mousecur to define how it interacts with
  788. existing characters on the screen.
  789.  
  790. Text Modes
  791.  
  792.      To change the mouse cursor in text modes, you must first define two 16-
  793. bit quantities called the screen mask and cursor mask.  The following figure
  794. defines the format of each mask.
  795.  
  796.                     bits      meaning
  797.  
  798.                     0 to 7    ASCII character value
  799.                     8 to 11   foreground color
  800.                     12 to 14  background color
  801.                     15        blink
  802.  
  803. Notice how this structure parallels the character and attribute bytes
  804. associated with each character cell.  The default screen mask is 77FF hex,
  805. and the default cursor mask is 7700 hex.
  806.  
  807.      When you position the mouse over a specific character cell, the mouse
  808. driver uses the current screen and cursor masks to determine the mouse
  809. cursor's appearance.  First, the mouse driver logically ANDs the screen mask
  810. with the existing contents of that character cell.  It then XORs that result
  811. with the cursor mask to display the mouse cursor.
  812.  
  813.      For example, consider how the mouse cursor is produced in the 80-column
  814. color text mode (mode 3).  Suppose a specific character cell contains the
  815. ASCII character 0 (48 decimal, 30 hex) and an attribute byte that specifies a
  816. white (color 15) foreground on a blue background (color 1) and does not blink
  817. (blink bit 0).  The binary structure of the character and its attribute are:
  818.  
  819.                             attribute    character
  820.  
  821.                             0 001 1111   00110000
  822.  
  823. Now let's see what happens when we apply the screen and cursor masks to the
  824. character and its attribute.
  825.  
  826.             attribute/character   0001 1111 0011 0000   (1F30 hex)
  827.             default screen mask   0111 0111 1111 1111   (77FF hex)
  828.                                   -------------------
  829.             result of AND         0001 0111 0011 0000   (1730 hex)
  830.  
  831. 274   Fastgraph User's Guide
  832.  
  833.  
  834.             default cursor mask   0111 0111 0000 0000   (7700 hex)
  835.                                   -------------------
  836.             result of XOR         0110 0000 0011 0000   (6030 hex)
  837.  
  838. The resulting character (30 hex) is the original character, but the new
  839. attribute (60 hex) represents a black foreground with a brown background and
  840. does not blink.  As long as the mouse cursor remains positioned on this
  841. character cell, it would appear black on brown.
  842.  
  843.      When we use the default screen and cursor masks, the mouse cursor will
  844. always display the original character and it will not blink.  The cursor
  845. foreground color will be 15-F, where F is the displayed character's
  846. foreground color.  Similarly, the cursor background color will be 7-B, where
  847. B is the displayed character's background color.  The default masks will
  848. virtually always produce a satisfactory mouse cursor.
  849.  
  850.      It is possible, however, to change the appearance of the mouse cursor in
  851. text modes by using your own screen and cursor masks.  The Fastgraph routine
  852. fg_mousecur does just that.  It expects two arguments, the first being the
  853. cursor mask and the second the screen mask.  Example 14-9 demonstrates the
  854. use of fg_mousecur.  The program displays some text and uses the default
  855. mouse cursor.  After waiting for a keystroke, the program calls fg_mousecur
  856. to define a new mouse cursor.  The new cursor is similar to the default
  857. cursor, but it displays the foreground colors in the opposite intensity as
  858. the default cursor.  The program then waits for another keystroke before
  859. returning to DOS.
  860.  
  861.                                 Example 14-9.
  862.  
  863.                   #include <fastgraf.h>
  864.                   #include <stdio.h>
  865.                   #include <stdlib.h>
  866.                   void main(void);
  867.  
  868.                   void main()
  869.                   {
  870.                      int old_mode;
  871.                      int row;
  872.  
  873.                      old_mode = fg_getmode();
  874.                      fg_setmode(3);
  875.  
  876.                      if (fg_mouseini() < 0) {
  877.                         fg_setmode(old_mode);
  878.                         fg_reset();
  879.                         exit(1);
  880.                         }
  881.  
  882.                      fg_setattr(7,0,0);
  883.                      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  884.  
  885.                      fg_setattr(12,7,0);
  886.                      for (row = 0; row < 25; row++) {
  887.                         fg_locate(row,34);
  888.                         fg_text("example 14-9",12);
  889.                         }
  890.                                        Chapter 14:  Input Device Support   275
  891.  
  892.  
  893.  
  894.                      fg_mousevis(1);
  895.                      fg_waitkey();
  896.                      fg_mousecur(0x7FFF,0x7F00);
  897.                      fg_waitkey();
  898.  
  899.                      fg_setmode(old_mode);
  900.                      fg_reset();
  901.                   }
  902.  
  903. Graphics Modes
  904.  
  905.      Defining the mouse cursor in graphics video modes also requires creating
  906. a screen mask and cursor mask, but as one might expect, the structure of
  907. these masks is vastly different from for text modes.  In fact, it closely
  908. resembles the mode-independent bit map format used by the fg_drawmap routine.
  909. Although their structure differs, the way the mouse driver applies the masks
  910. is the same as in the text modes.  That is, the driver displays the mouse
  911. cursor by first logically ANDing video memory with the screen mask, and then
  912. XORing that result with the cursor mask.
  913.  
  914.      Let's begin by looking at the masks for the default mouse cursor in
  915. graphics modes.  The size of each mask (and hence the mouse cursor) is 16
  916. pixels wide and 16 pixels high.  As mentioned earlier, the default cursor is
  917. a small white arrow with a black outline around it.  Here are its screen and
  918. cursor masks expressed as binary values.
  919.  
  920.               screen                cursor                cursor
  921.                mask                  mask               appearance
  922.  
  923.          1001111111111111      0000000000000000       **
  924.          1000111111111111      0010000000000000       *x*
  925.          1000011111111111      0011000000000000       *xx*
  926.          1000001111111111      0011100000000000       *xxx*
  927.          1000000111111111      0011110000000000       *xxxx*
  928.          1000000011111111      0011111000000000       *xxxxx*
  929.          1000000001111111      0011111100000000       *xxxxxx*
  930.          1000000000111111      0011111110000000       *xxxxxxx*
  931.          1000000000011111      0011111111000000       *xxxxxxxx*
  932.          1000000000001111      0011111000000000       *xxxxx*****
  933.          1000000011111111      0011011000000000       *xx*xx*
  934.          1000100001111111      0010001100000000       *x* *xx*
  935.          1001100001111111      0000001100000000       **  *xx*
  936.          1111110000111111      0000000110000000            *xx*
  937.          1111110000111111      0000000110000000            *xx*
  938.          1111111000111111      0000000000000000             ***
  939.  
  940.      The mouse driver first ANDs the screen mask with video memory at the
  941. mouse cursor position.  This means the screen mask 1 bits leave video memory
  942. intact, while the 0 bits change the corresponding pixels to black.  Next, the
  943. mouse driver XORs the result with the cursor mask.  This time the cursor mask
  944. 0 bits leave video memory unchanged, while the 1 bits change the
  945. corresponding pixels to white.  This produces a mouse cursor as shown above
  946. on the right, where a dot ( ) represents an unchanged pixel, an asterisk (*)
  947. a black pixel, and an x a white pixel.  The following table summarizes the
  948. cursor appearance for all possible combinations of mask bits.
  949. 276   Fastgraph User's Guide
  950.  
  951.  
  952.         screen mask bit     cursor mask bit resulting cursor pixel
  953.  
  954.                0                   0                 black
  955.                0                   1                 white
  956.                1                   0               unchanged
  957.                1                   1               inverted
  958.  
  959.      The color of an "inverted" pixel is n-k, where n is the maximum color
  960. number in the current video mode, and k is the color of the pixel being
  961. replaced.  Also, "black" and "white" pixels are not necessarily these colors
  962. in 16-color and 256-color modes.  More correctly, "black" pixels are
  963. displayed in the color assigned to palette 0, and "white" pixels are the
  964. displayed in the color assigned to palette 15 (255 in XVGA and SVGA 256-color
  965. modes).  If you're using the CGA color modes, "black" pixels are displayed in
  966. the background color, and "white" pixels appear in color 3 (whose actual
  967. color is determined by the selected CGA palette).
  968.  
  969.      With an understanding of the way the default mouse cursor works in
  970. graphics modes, we're now ready to define our own mouse cursor.  Shown below
  971. are the screen mask, cursor mask, and resulting appearance for a solid plus-
  972. shaped cursor.  The hexadecimal equivalents of the binary mask values are
  973. also given.
  974.  
  975.    ----- screen mask ----      ----- cursor mask ----
  976.                                                                 cursor
  977.         binary       hex            binary       hex          appearance
  978.  
  979.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  980.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  981.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  982.    0000000000000111  0007      0000111110000000  0F80      ****xxxxx****...
  983.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  984.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  985.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  986.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  987.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  988.    0000000000000111  0007      0000111110000000  0F80      ****xxxxx****...
  989.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  990.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  991.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  992.    1111111111111111  FFFF      0000000000000000  0000      ................
  993.    1111111111111111  FFFF      0000000000000000  0000      ................
  994.    1111111111111111  FFFF      0000000000000000  0000      ................
  995.  
  996. If we wanted to make the mouse cursor hollow rather than solid, the masks and
  997. resulting cursor appearance would look like this.
  998.  
  999.    ----- screen mask ----      ----- cursor mask ----
  1000.                                                                 cursor
  1001.         binary       hex            binary       hex          appearance
  1002.  
  1003.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  1004.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1005.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1006.    0000111110000111  0F87      0000000000000000  0000      ****.....****...
  1007.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1008.                                        Chapter 14:  Input Device Support   277
  1009.  
  1010.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1011.    0111111111110111  7FF7      0000001000000000  0200      *.....x.....*...
  1012.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1013.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1014.    0000111110000111  0F87      0000000000000000  0000      ****.....****...
  1015.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1016.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1017.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  1018.    1111111111111111  FFFF      0000000000000000  0000      ................
  1019.    1111111111111111  FFFF      0000000000000000  0000      ................
  1020.    1111111111111111  FFFF      0000000000000000  0000      ................
  1021.  
  1022. Note that the center bit defined in the cursor mask causes the corresponding
  1023. pixel in video memory to be inverted.
  1024.  
  1025.      There is one more item needed to define a graphics mode mouse cursor
  1026. completely.  That item is the hot spot, or the actual screen position used or
  1027. reported by the mouse driver.  For the plus-shaped cursors just constructed,
  1028. it would be sensible to define the hot spot in the center of the plus.  The
  1029. hot spot is specified relative to the upper left corner of the cursor, so its
  1030. position within the cursor would be (6,6) -- that is, six pixels to the right
  1031. and six pixels below the upper left corner.  You can specify the hot spot
  1032. offsets using negative values or values above 15 to position it outside the
  1033. mouse cursor matrix if desired.
  1034.  
  1035.      The Fastgraph routine fg_mouseptr defines a mouse cursor in graphics
  1036. modes.  The first of its three arguments is a 32-element integer array,
  1037. passed by reference.  The array's first 16 elements contain the screen mask,
  1038. and its second 16 elements contain the cursor mask.  The remaining two
  1039. arguments respectively specify the horizontal and vertical offsets for the
  1040. hot spot.  The fg_mouseptr routine has no effect in a text video mode.
  1041.  
  1042.      Example 14-10 is similar to example 14-9.  It shows how to define a
  1043. graphics mode mouse cursor using fg_mouseptr.  The values stored in the solid
  1044. and hollow arrays define the screen and cursor masks for the solid and hollow
  1045. plus-shaped mouse cursors discussed earlier.  After making the mouse cursor
  1046. visible, the program uses the default mouse cursor until a key is pressed.
  1047. Following this, it changes to the solid cursor.  After another keystroke, the
  1048. program changes to the hollow cursor.  When you run example 14-10, compare
  1049. the differences among the three mouse cursors.
  1050.  
  1051.                                 Example 14-10.
  1052.  
  1053.   #include <fastgraf.h>
  1054.   #include <stdio.h>
  1055.   #include <stdlib.h>
  1056.   void main(void);
  1057.  
  1058.   int solid[]  = {0xE03F,0xE03F,0xE03F,0x0007,0x0007,0x0007,0x0007,0x0007,
  1059.                   0x0007,0x0007,0xE03F,0xE03F,0xE03F,0xFFFF,0xFFFF,0xFFFF,
  1060.                   0x0000,0x0F80,0x0F80,0x0F80,0x7FF0,0x7FF0,0x7FF0,0x7FF0,
  1061.                   0x7FF0,0x0F80,0x0F80,0x0F80,0x0000,0x0000,0x0000,0x0000};
  1062.  
  1063.   int hollow[] = {0xE03F,0xEFBF,0xEFBF,0x0F87,0x7FF7,0x7FF7,0x7FF7,0x7FF7,
  1064.                   0x7FF7,0x0F87,0xEFBF,0xEFBF,0xE03F,0xFFFF,0xFFFF,0xFFFF,
  1065.                   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0200,0x0000,
  1066.                   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
  1067. 278   Fastgraph User's Guide
  1068.  
  1069.  
  1070.   void main()
  1071.   {
  1072.      int old_mode;
  1073.      int column, row, last_row;
  1074.  
  1075.      old_mode = fg_getmode();
  1076.      fg_setmode(fg_automode());
  1077.  
  1078.      if (fg_mouseini() < 0) {
  1079.         fg_setmode(old_mode);
  1080.         fg_reset();
  1081.         exit(1);
  1082.         }
  1083.  
  1084.      fg_setcolor(15);
  1085.      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  1086.  
  1087.      fg_setcolor(12);
  1088.      column = fg_xalpha(fg_getmaxx()/2) - 6;
  1089.      last_row = fg_yalpha(fg_getmaxy()) + 1;
  1090.  
  1091.      for (row = 0; row < last_row; row++) {
  1092.         fg_locate(row,column);
  1093.         fg_text("example 14-10",13);
  1094.         }
  1095.  
  1096.      fg_mousevis(1);
  1097.      fg_waitkey();
  1098.      fg_mouseptr(solid,6,6);
  1099.      fg_waitkey();
  1100.      fg_mouseptr(hollow,6,6);
  1101.      fg_waitkey();
  1102.  
  1103.      fg_setmode(old_mode);
  1104.      fg_reset();
  1105.   }
  1106.  
  1107.  
  1108. CGA Considerations
  1109.  
  1110.      The mouse driver treats the screen and cursor masks differently in the
  1111. CGA four-color graphics modes (modes 4 and 5) than in the other graphics
  1112. modes.  In the CGA modes, each pair of mask bits corresponds to one pixel.
  1113. This means the masks more closely resemble the mode-specific format used by
  1114. fg_drwimage instead of the mode-independent format of fg_drawmap.
  1115.  
  1116.      Fastgraph uses a different default mouse cursor for modes 4 and 5.  Its
  1117. screen and cursor masks, as well as the resulting cursor appearance, are
  1118. shown in the following diagram.
  1119.  
  1120.                 screen                  cursor              cursor
  1121.                 mask                    mask             appearance
  1122.  
  1123.            0000111111111111        0000000000000000        **
  1124.            0000001111111111        0011000000000000        ***
  1125.            0000000011111111        0011110000000000        ****
  1126.                                        Chapter 14:  Input Device Support   279
  1127.  
  1128.  
  1129.            0000000000111111        0011111100000000        *****
  1130.            0000000000001111        0011111111000000        ******
  1131.            0000000000000011        0011111111110000        *******
  1132.            0000000000000011        0011111100000000        *******
  1133.            0000000000111111        0011111110000000        *****
  1134.            0000000000001111        0011000011000000        ******
  1135.            0000110000001111        0000000011000000        ** ***
  1136.            1111111100000011        0000000000110000            ***
  1137.            1111111100000011        0010000000110000            ***
  1138.            1111111111000011        0000000000000000             **
  1139.            1111111111111111        0000000000000000
  1140.            1111111111111111        0000000000000000
  1141.            1111111111111111        0000000000000000
  1142.  
  1143. As you can see, the resulting mouse cursor is eight pixels wide instead of
  1144. 16.
  1145.  
  1146.      Another important point concerning mouse cursors in modes 4 and 5 is the
  1147. chance of pixel bleeding, or the changing of colors within the mouse cursor
  1148. as it moves horizontally.  Bleeding will occur if you use the bit pairs 01 or
  1149. 10 in either mask to represent a pixel.  In the default masks for modes 4 and
  1150. 5, note that only the binary values 00 and 11 appear as bit pairs.  Keep this
  1151. in mind if you create your own masks in these video modes.
  1152.  
  1153.  
  1154. Joystick Support
  1155.  
  1156.      The third type of input device supported by Fastgraph is the joystick.
  1157. Although joysticks are not as popular as mice, they are often preferable when
  1158. a user's reactions are critical, such as in an arcade-style game.  Fastgraph
  1159. includes routines for initializing a joystick, reading a joystick's position
  1160. or button status, and making a joystick behave analogously to the keyboard.
  1161. These routines are independent of the rest of Fastgraph and thus do not
  1162. require that you first call the fg_setmode routine.
  1163.  
  1164.      Joysticks are connected to a system through a game port.  The PCjr and
  1165. Tandy 1000 systems come equipped with two game ports, and hence support two
  1166. joysticks.  On other systems in the IBM family, you can install a game port
  1167. card that contains either one or two game ports.  If the card only has one
  1168. game port, you can use a splitter cable to fork two joysticks into the port.
  1169.  
  1170.  
  1171. Initializing Joysticks
  1172.  
  1173.      Before you can use any of Fastgraph's joystick support routines with a
  1174. specific joystick, you must initialize that joystick.  The fg_initjoy routine
  1175. performs this task.  This routine requires a single integer argument that
  1176. specifies which joystick to initialize, either 1 or 2.  If successful,
  1177. fg_initjoy returns 0 as the function value.  If the machine has no game port,
  1178. or if the requested joystick is not connected to the game port, fg_initjoy
  1179. returns -1.  When you use fg_initjoy, the joystick being initialized must be
  1180. centered (that is, the stick itself must not be tilted in either direction).
  1181.  
  1182.      Example 14-11 uses the fg_initjoy routine to try to initialize both
  1183. joysticks.  For each joystick, the program prints a message stating whether
  1184. or not the initialization was successful.
  1185. 280   Fastgraph User's Guide
  1186.  
  1187.  
  1188.                                 Example 14-11.
  1189.  
  1190.                  #include <fastgraf.h>
  1191.                  #include <stdio.h>
  1192.                  void main(void);
  1193.  
  1194.                  void main()
  1195.                  {
  1196.                     if (fg_initjoy(1) < 0)
  1197.                        printf("Joystick 1 not available.\n");
  1198.                     else
  1199.                        printf("Joystick 1 found.\n");
  1200.  
  1201.                     if (fg_initjoy(2) < 0)
  1202.                        printf("Joystick 2 not available.\n");
  1203.                     else
  1204.                        printf("Joystick 2 found.\n");
  1205.                  }
  1206.  
  1207.  
  1208.  
  1209. Reporting Joystick Status
  1210.  
  1211.      Each joystick can report three items:  its horizontal position, its
  1212. vertical position, and the button status.  Fastgraph includes routines for
  1213. obtaining each of these quantities.
  1214.  
  1215.      The fg_getxjoy and fg_getyjoy routines respectively return the
  1216. horizontal and vertical position of the indicated joystick.  Both routines
  1217. require a single integer argument, whose value is either 1 or 2, to identify
  1218. the joystick.  The requested position is returned as the function value.
  1219. Horizontal coordinates increase as the joystick moves to the right, while
  1220. vertical coordinates increase as the joystick moves downward.  If fg_initjoy
  1221. did not initialize the specified joystick, or if your program hasn't yet
  1222. called fg_initjoy, both fg_getxjoy and fg_getyjoy will return the value -1.
  1223.  
  1224.      Joystick characteristics vary more than those of any other input device.
  1225. The values returned by fg_getxjoy and fg_getyjoy depend on the system's
  1226. processor speed and the brand of joystick used.  It often suffices to know
  1227. the joystick position relative to its previous position, in which case the
  1228. actual coordinate values do not matter.  However, if you must rely on
  1229. specific coordinate values, your program must perform some type of manual
  1230. joystick calibration and then scale the coordinates reported by fg_getxjoy
  1231. and fg_getyjoy as needed.
  1232.  
  1233.      The other piece of information joysticks provide is the button status.
  1234. Most joysticks have two buttons, called the top and bottom buttons.  Others
  1235. have three buttons, but one of them duplicates the functionality of another
  1236. (for example, a joystick might have one bottom button on its left side and
  1237. another on its right side).  The Fastgraph routine fg_button returns the
  1238. joystick button status as its function value.  Like fg_getxjoy and
  1239. fg_getyjoy, the fg_button routine requires a single argument that specifies
  1240. the joystick number.  The meaning of the returned value is shown below.
  1241.                                        Chapter 14:  Input Device Support   281
  1242.  
  1243.                   value  meaning
  1244.  
  1245.                     0    neither button pressed
  1246.                     1    top button pressed
  1247.                     2    bottom button pressed
  1248.                     3    top and bottom buttons pressed
  1249.  
  1250.      You don't need to call fg_initjoy before using fg_button.  If the
  1251. specified joystick is not present, the fg_button routine will return zero.
  1252.  
  1253.      Example 14-12 uses fg_getxjoy, fg_getyjoy, and fg_button to poll both
  1254. joysticks at half-second intervals.  It then displays the joystick number (1
  1255. or 2), horizontal position, vertical position, and button status for each
  1256. joystick.  As the program runs, you can move the joysticks and watch how the
  1257. movements affect the displayed coordinate values.  The program continues
  1258. doing this until you press Ctrl/C or Ctrl/Break to stop it.
  1259.  
  1260.                                 Example 14-12.
  1261.  
  1262.                   #include <fastgraf.h>
  1263.                   #include <stdio.h>
  1264.                   void main(void);
  1265.                   void main()
  1266.                   {
  1267.                      int b, x, y;
  1268.  
  1269.                      fg_initjoy(1);
  1270.                      fg_initjoy(2);
  1271.  
  1272.                      while (1) {
  1273.                         x = fg_getxjoy(1);
  1274.                         y = fg_getyjoy(1);
  1275.                         b = fg_button(1);
  1276.                         printf("1:  %3d %3d %1d\n",x,y,b);
  1277.                         x = fg_getxjoy(2);
  1278.                         y = fg_getyjoy(2);
  1279.                         b = fg_button(2);
  1280.                         printf("2:  %3d %3d %1d\n\n",x,y,b);
  1281.                         fg_waitfor(9);
  1282.                         }
  1283.                   }
  1284.  
  1285.      There are two ways of effectively monitoring joystick button status.
  1286. One is to call fg_button at many places in your program and then take the
  1287. necessary action depending on the button status.  However, the preferable
  1288. method is to extend the BIOS time-of-day interrupt to check the button status
  1289. at each clock tick (there are 18.2 clock ticks per second), set a flag if a
  1290. button is pressed, and then check the flag as needed in your program.
  1291. Information on changing the BIOS time-of-day interrupt appears in Appendix C
  1292. of this document.
  1293.  
  1294.  
  1295. Keyboard Emulation
  1296.  
  1297.      Although we can use the fg_getxjoy and fg_getyjoy routines to monitor
  1298. relative joystick movements, it is usually easier to do this with another
  1299. Fastgraph routine, fg_intjoy.  This routine is similar to the fg_intkey
  1300. 282   Fastgraph User's Guide
  1301.  
  1302.  
  1303. routine in that it returns two values that are equivalent to the standard or
  1304. extended keyboard codes for analogous keystrokes.
  1305.  
  1306.      The fg_intjoy routine needs three arguments.  The first argument
  1307. specifies the joystick number, either 1 or 2.  The second and third
  1308. arguments, both one-byte quantities passed by reference, receive the standard
  1309. and extended keyboard codes analogous to the joystick movement and button
  1310. status.  The second argument receives a value of 13 (the standard keyboard
  1311. code for the Enter key) if any joystick button is pressed; it receives a
  1312. value of 0 if not.  The third argument receives a value corresponding to the
  1313. extended keyboard code for one of the directional keys on the numeric keypad,
  1314. as summarized in the following table.
  1315.  
  1316.        joystick position   corresponding key   extended key code
  1317.  
  1318.           up and left            Home                 71
  1319.               up               up arrow               72
  1320.          up and right            PgUp                 73
  1321.              left             left arrow              75
  1322.            centered           (no action)              0
  1323.              right            right arrow             77
  1324.          down and left            End                 79
  1325.              down             down arrow              80
  1326.         down and right           PgDn                 81
  1327.  
  1328. The fg_intjoy routine will set both key code arguments to zero if the
  1329. specified joystick has not yet been initialized.
  1330.  
  1331.      Example 14-13 is similar to example 14-11, but it uses fg_intjoy in
  1332. place of fg_getxjoy and fg_getyjoy to report relative joystick position.
  1333. This program does not report the joystick button status as example 14-11
  1334. does, but you could readily add this feature to it.
  1335.  
  1336.                                 Example 14-13.
  1337.  
  1338.                    #include <fastgraf.h>
  1339.                    #include <stdio.h>
  1340.                    void main(void);
  1341.  
  1342.                    void main()
  1343.                    {
  1344.                       char key, aux;
  1345.  
  1346.                       fg_initjoy(1);
  1347.                       fg_initjoy(2);
  1348.  
  1349.                       while (1) {
  1350.                          fg_intjoy(1,&key,&aux);
  1351.                          printf("1: %2d %2d\n",key,aux);
  1352.                          fg_intjoy(2,&key,&aux);
  1353.                          printf("2: %2d %2d\n\n",key,aux);
  1354.                          fg_waitfor(9);
  1355.                          }
  1356.                    }
  1357.  
  1358.                                        Chapter 14:  Input Device Support   283
  1359.  
  1360.  
  1361. Special Joystick Considerations
  1362.  
  1363.      If you develop a program that supports only one joystick, you should use
  1364. joystick 1.  The reasons for this are twofold.  First, it will make your
  1365. program consistent with most other products that support joysticks.  Second,
  1366. and perhaps more importantly, many Tandy 1000 series machines cannot
  1367. determine if joystick 2 is present when neither joystick is connected.  This
  1368. means if you use joystick 2 instead of joystick 1 in a single joystick
  1369. program, you won't be able to tell if a joystick is available when running on
  1370. a Tandy 1000.
  1371.  
  1372.  
  1373. Summary of Input Routines
  1374.  
  1375.      This section summarizes the functional descriptions of the Fastgraph
  1376. routines presented in this chapter.  More detailed information about these
  1377. routines, including their arguments and return values, may be found in the
  1378. Fastgraph Reference Manual.
  1379.  
  1380.      FG_BUTTON returns information about the state of either joystick's
  1381. buttons.
  1382.  
  1383.      FG_CAPSLOCK determines the state of the CapsLock key.
  1384.  
  1385.      FG_GETKEY waits for a keystroke (or reads the next entry from the BIOS
  1386. keyboard buffer). It returns the keystroke's standard or extended keyboard
  1387. code.
  1388.  
  1389.      FG_GETXJOY and FG_GETYJOY return the horizontal and vertical coordinate
  1390. position of the specified joystick.  The actual coordinates depend on the
  1391. processor speed and brand of joystick used.
  1392.  
  1393.      FG_INITJOY initializes joystick 1 or 2 and must be called before using
  1394. fg_getxjoy, fg_getyjoy, or fg_intjoy.  It returns a status code indicating
  1395. whether or not the initialization was successful.
  1396.  
  1397.      FG_INTJOY returns the standard and extended keyboard codes analogous to
  1398. the current position and button status of the specified joystick.
  1399.  
  1400.      FG_INTKEY reads the next entry from the BIOS keyboard buffer and returns
  1401. the keystroke's standard or extended keyboard code.  It is similar to
  1402. fg_getkey, but it does not wait for a keystroke if the keyboard buffer is
  1403. empty.
  1404.  
  1405.      FG_KBINIT enables or disables the Fastgraph low-level keyboard handler.
  1406. If the keyboard handler is already in the requested state, nothing happens.
  1407.  
  1408.      FG_KBTEST determines if the key having the specified scan code is now
  1409. pressed or released.  The low-level keyboard handler must be enabled for this
  1410. routine to work properly.
  1411.  
  1412.      FG_MOUSEBUT returns information about mouse button press or release
  1413. counts, as well as the mouse cursor position at the time of the last button
  1414. press or release.
  1415. 284   Fastgraph User's Guide
  1416.  
  1417.  
  1418.      FG_MOUSECUR defines the appearance of the mouse cursor in text video
  1419. modes.
  1420.  
  1421.      FG_MOUSEFIN unhooks Fastgraph's XVGA or SVGA mouse handler from the
  1422. mouse driver.  This routine should be used just before reverting to text mode
  1423. in programs that have called fg_mouseini in XVGA or SVGA graphics modes.  It
  1424. has no effect in other video modes.
  1425.  
  1426.      FG_MOUSEINI initializes the mouse and must be called before any of
  1427. Fastgraph's other mouse support routines.  It returns an error status if the
  1428. mouse driver has not been loaded, or if the mouse is not connected.
  1429.  
  1430.      FG_MOUSELIM defines the rectangular area in which the mouse cursor may
  1431. move.
  1432.  
  1433.      FG_MOUSEMOV moves the mouse cursor to the specified character cell (in
  1434. text modes) or screen space position (in graphics modes).
  1435.  
  1436.      FG_MOUSEPOS returns the current mouse position and button status.
  1437.  
  1438.      FG_MOUSEPTR defines the shape and appearance of the mouse cursor in
  1439. graphics video modes.
  1440.  
  1441.      FG_MOUSESPD defines the number of mickey units per eight pixels of
  1442. cursor movement.  This effectively controls the speed at which the mouse
  1443. cursor moves relative to the movement of the mouse itself.
  1444.  
  1445.      FG_MOUSEVIS makes the mouse cursor visible or invisible.
  1446.  
  1447.      FG_NUMLOCK determines the state of the NumLock key.
  1448.  
  1449.      FG_SCRLOCK determines the state of the ScrollLock key (which is not
  1450. present on some keyboards).
  1451.  
  1452.      FG_SETCAPS controls the state of the CapsLock key.
  1453.  
  1454.      FG_SETNUM controls the state of the NumLock key.
  1455.  
  1456.      FG_WAITKEY flushes the BIOS keyboard buffer (that is, removes any type-
  1457. ahead characters) and then waits for another keystroke.
  1458.